#pragma once
/*
    日志器模块：对于之前的所有模块进行整合，向外提供接口完成不同等级日志的输出
                                限制等级模块：只有当日志等级大于等于这个等级才会进行输出
    管理的成员：
        1. 格式化模块对象
        2. 落地模块对象（是一个数组，因为同一个日志器可能会存在不同的输出方向）
        3. 默认输出等级限制
        4. 互斥锁（保证多线程下的线程安全，防止出现‘交叉日志’）
        5. 日志器名称 （日志器唯一标识）
    提供的方法:
        1. debug -- fatal等级日志的不同输出操作
*/

/*
    抽象一个基类Logger ，主要用来派生出两种落地方式 同步 or 异步
        同步：直接写磁盘
        异步：先存在内存缓冲区，再定义一个异步线程处理这个缓冲区
*/

#include "1_util.hpp"
#include "2_level.hpp"
#include "3_msg.hpp"
#include "4_format.hpp"
#include "5_logSink.hpp"
#include "6_buffer.hpp"
#include "7_lopper.hpp"

#include <atomic>
#include <mutex>
#include <unordered_map>

#include <cstdarg> //不定参

namespace senlog
{
    class Logger
    {
    protected:
        std::string _logger_name;
        std::atomic<LogLevel::value> _limit_value; // 原子类原因：限制等级在每次输出日志的时候都会访问，那么容易出现锁冲突
        Formatter::ptr _formatter;                 // 格式化器
        std::vector<LogSink::ptr> _sinks;          // 落地方向
        std::mutex _mutex;

    public:
        Logger(const std::string &logger_name,
               LogLevel::value level,
               Formatter::ptr &formatter,
               std::vector<LogSink::ptr> sinks)
            : _logger_name(logger_name), _limit_value(level), _formatter(formatter), _sinks(sinks.begin(), sinks.end())
        {
        }

    public:
        using ptr = std::shared_ptr<Logger>;

        // 完成构造日志消息对象过程并格式化，得到格式化后的日志字符串
        void debug(const std::string &filename, size_t line, const std::string &fmt, ...)
        {
            // 1. 判断是否达到输出等级
            if (LogLevel::value::DEBUG < _limit_value)
                return; // 不能输出

            // 2. 可以输出_> 对不定参进行解析格式化
            va_list ap;
            va_start(ap, fmt);
            char *res;
            int ret = vasprintf(&res, fmt.c_str(), ap);
            if (ret == -1)
            {
                // err
                std::cout << "vasprintf error" << std::endl;
                return;
            }
            va_end(ap);

            // 3. 接收完全参数后，将参数传给LogMsg 开始构建日志信息对象
            LogMsg msg(LogLevel::value::DEBUG, line, filename, _logger_name, res);

            // 4. 对日志信息对象进行格式化
            std::stringstream ss;
            _formatter->format(ss, msg);

            // 5.日志落地
            log(ss.str().c_str(), ss.str().size());
            free(res); // 资源泄漏
        }
        void info(const std::string &filename, size_t line, const std::string &fmt, ...)
        {
            if (LogLevel::value::INFO < _limit_value)
                return;
            va_list ap;
            va_start(ap, fmt);
            char *res;
            int ret = vasprintf(&res, fmt.c_str(), ap);
            if (ret == -1)
                std::cout << "vasprintf err" << std::endl;
            LogMsg msg(LogLevel::value::INFO, line, filename, _logger_name, res);
            std::stringstream ss;
            _formatter->format(ss, msg);
            log(ss.str().c_str(), ss.str().size());
            free(res);
        }
        void warn(const std::string &filename, size_t line, const std::string &fmt, ...)
        {
            if (LogLevel::value::WARN < _limit_value)
                return;
            va_list ap;
            va_start(ap, fmt);
            char *res;
            int ret = vasprintf(&res, fmt.c_str(), ap);
            if (ret == -1)
                std::cout << "vasprintf err" << std::endl;
            LogMsg msg(LogLevel::value::WARN, line, filename, _logger_name, res);
            std::stringstream ss;
            _formatter->format(ss, msg);
            log(ss.str().c_str(), ss.str().size());
            free(res);
        }
        void error(const std::string &filename, size_t line, const std::string &fmt, ...)
        {
            if (LogLevel::value::ERROR < _limit_value)
                return;
            va_list ap;
            va_start(ap, fmt);
            char *res;
            int ret = vasprintf(&res, fmt.c_str(), ap);
            if (ret == -1)
                std::cout << "vasprintf err" << std::endl;
            LogMsg msg(LogLevel::value::ERROR, line, filename, _logger_name, res);
            std::stringstream ss;
            _formatter->format(ss, msg);
            log(ss.str().c_str(), ss.str().size());
            free(res);
        }
        void fatal(const std::string &filename, size_t line, const std::string &fmt, ...)
        {
            if (LogLevel::value::FATAL < _limit_value)
                return;
            va_list ap;
            va_start(ap, fmt);
            char *res;
            int ret = vasprintf(&res, fmt.c_str(), ap);
            if (ret == -1)
                std::cout << "vasprintf err" << std::endl;
            LogMsg msg(LogLevel::value::FATAL, line, filename, _logger_name, res);
            std::stringstream ss;
            _formatter->format(ss, msg);
            log(ss.str().c_str(), ss.str().size());
            free(res);
        }
        const std::string& name()
        {
            return _logger_name;
        }
    protected:
        // log 接口完成实际的字符串落地输出，派生不同的落地方式：同步、异步
        virtual void log(const char *data, size_t len) = 0;
    };

    class SyncLogger : public Logger // 同步: 直接通过落地方式模块进行日志落地
    {
        // 同步落地参数
    public:
        SyncLogger(const std::string &logger_name,
                   LogLevel::value level,
                   Formatter::ptr &formatter,
                   std::vector<LogSink::ptr> sinks)
            : Logger(logger_name, level, formatter, sinks)
        {
        }
        virtual void log(const char *data, size_t len)
        {
            std::unique_lock<std::mutex> lock(_mutex); // 自动加锁
            if (_sinks.empty())
                return;
            for (auto &sink : _sinks)
            {
                sink->Log(data, len);
            }
        }
    };
    class AsyncLogger : public Logger
    {
        // 异步落地参数
    private:
        AsynLooper::ptr _lopper;

    public:
        AsyncLogger(const std::string &logger_name,
                    LogLevel::value level,
                    Formatter::ptr &formatter,
                    std::vector<LogSink::ptr> sinks,
                    AsyncType type)
            : Logger(logger_name, level, formatter, sinks), _lopper(std::make_shared<AsynLooper>(std::bind(&AsyncLogger::realLog, this, std::placeholders::_1), type))
        {
        } // bind 的用法
        virtual void log(const char *data, size_t len)
        {
            _lopper->push(data, len);
        }
        // 一个实际落地函数
        void realLog(Buffer &buffer)
        {
            if (_sinks.empty())
                return;
            for (auto &sink : _sinks)
            {
                sink->Log(buffer.readableBegin(), buffer.readableSize());
            }
        }
    };

    // 使用建造者模式来建造日志器
    // 简化了用户的使用复杂度

    //(不需要指挥者)
    // 1. 抽象一个建造者类
    enum class LoggerType
    {
        SYNC_LOGGER, // 同步
        ASYN_LOGGER  // 异步
    };
    class LoggerBuilder
    {
        // 所有组件的构建
    protected:
        AsyncType _lopper_type;
        LoggerType _logger_type;
        std::string _logger_name;
        std::atomic<LogLevel::value> _limit_value; // 原子类原因：限制等级在每次输出日志的时候都会访问，那么容易出现锁冲突
        Formatter::ptr _formatter;                 // 格式化器
        std::vector<LogSink::ptr> _sinks;          // 落地方向
    public:
        LoggerBuilder()
            : _logger_type(LoggerType::SYNC_LOGGER), _limit_value(LogLevel::value::DEBUG), _lopper_type(AsyncType::ASYNC_SAFE)
        {
        }

    public:
        void buildEnableUnsafe()
        {
            _lopper_type = AsyncType::ASYNC_UUNSAFE;
        }

        void buildLoggerType(LoggerType type)
        {
            _logger_type = type;
        }
        void buildLoggerName(const std::string name)
        {
            _logger_name = name;
        }
        void buildLimitValue(LogLevel::value value)
        {
            _limit_value = value;
        }
        void buildFormatterPtr(const std::string &pattern)
        {
            _formatter = std::make_shared<Formatter>(pattern);
        }
        template <typename SinkType, typename... Args>
        void buildSink(Args &&...args) // 不同落地器的创建
        {
            auto psink = SinkFactory::create<SinkType>(std::forward<Args>(args)...);
            _sinks.push_back(psink);
        }

        virtual Logger::ptr build() = 0; // 最终组装
    };

    // 2. 派生具体的建造者类
    class LocalLoggerBuilder : public LoggerBuilder
    {
    public:
        virtual Logger::ptr build() override
        {
            assert(_logger_name.empty() == false);
            if (_formatter.get() == nullptr)
            {
                _formatter = std::make_shared<Formatter>();
            }
            if (_sinks.empty() == true)
            {
                buildSink<StdoutLogSink>();
            }
            if (_logger_type == LoggerType::ASYN_LOGGER)
            {
                // 异步
                return std::make_shared<AsyncLogger>(_logger_name, _limit_value, _formatter, _sinks, _lopper_type);
                // 创建异步线程
            }
            else
            {
                // 同步
                return std::make_shared<SyncLogger>(_logger_name, _limit_value, _formatter, _sinks);
            }
        }
    };

    // 日志器管理类 （单例模式）
    /*
        在项目的任意位置都可以使用该系统

        1. 对所创建的日志器进行管理
        2. 增加全局统一日志器访问点
        3. 拓展：单例创建时，默认日志器用于标准输出的打印

        成员：
            默认日志器
            管理的日志器数组
            互斥锁【避免多线程对上面数组资源】
        方法:
            添加日志器管理
            是否包含某个日志器
            获取指定日志器
            获取默认日志器
    */
    class LoggerManager //懒汉单例模式
    {
    private:
        std::mutex _mutex;
        Logger::ptr _defalut_logger;
        std::unordered_map<std::string, Logger::ptr> _loggers;

    private:
        LoggerManager()
         {
            std::unique_ptr<senlog::LoggerBuilder> builder(new senlog::LocalLoggerBuilder());
            builder->buildLoggerName("deafult");
            _defalut_logger = builder->build();
            _loggers.insert(std::make_pair("deafult", _defalut_logger));
         }

    public:
        static LoggerManager& GetInstance()
        {
            static LoggerManager _inst; //C++11后，静态局部变量在编译层面是线程安全的【当前线程没有构造完成前，其他线程会阻塞】
            return _inst;
        }
        void addLogger(Logger::ptr &logger)
        {
            if(hasLogger(logger->name())) 
                return;
            std::unique_lock<std::mutex> lock(_mutex);
            _loggers.insert(std::make_pair(logger->name(), logger));//名称 于 类的映射
        }
        bool hasLogger(const std::string &name)
        {
            std::unique_lock<std::mutex> lock(_mutex);
            auto it = _loggers.find(name);
            if(it == _loggers.end()) 
                return false;
            return true;
        }
        Logger::ptr getLogger(const std::string &name)
        {
            std::unique_lock<std::mutex> lock(_mutex);
            auto it = _loggers.find(name);
            if(it == _loggers.end())
                return nullptr;
            return it->second;
        }
        Logger::ptr gerDefalutLogger()
        {
            return _defalut_logger;
        }
    };


    //简化用户操作：设计一个全局模式的建造者
    class GlobalLoggerBuilder : public LoggerBuilder
    {
    public:
        virtual Logger::ptr build() override
        {
            assert(_logger_name.empty() == false);
            if (_formatter.get() == nullptr)
            {
                _formatter = std::make_shared<Formatter>();
            }
            if (_sinks.empty() == true)
            {
                buildSink<StdoutLogSink>();
            }
            Logger::ptr logger;

            if (_logger_type == LoggerType::ASYN_LOGGER)
            {
                // 异步
                logger = std::make_shared<AsyncLogger>(_logger_name, _limit_value, _formatter, _sinks, _lopper_type);
                // 创建异步线程
            }
            else
            {
                // 同步
                logger = std::make_shared<SyncLogger>(_logger_name, _limit_value, _formatter, _sinks);
            }
            
            LoggerManager::GetInstance().addLogger(logger);
            return logger;
        }
    };
};